
/* GCSx
** SPRITE.H
**
** Sprite support (no edit-specific version)
*/

/*****************************************************************************
** Copyright (C) 2003-2006 Janson
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
*****************************************************************************/

#ifndef __GCSx_SPRITE_H_
#define __GCSx_SPRITE_H_

// Intentionally kept as simple and fast as possible-
//  no virtual table, some inline property sets
// @TODO: derive from ObjectBase, handle everythine associated with that
class Sprite : public ObjectBase {
public:
    enum {
        DEFAULT_PRIORITY = 100
    };

    // Scripting-accessible properties
    enum {
        // Position within layer (can be outside bounds)
        PROP_X = 0,
        PROP_Y,

        // Origin can be offset
        // Added/deleted to x/y automatically
        PROP_ORIGIN_X,
        PROP_ORIGIN_Y,
        
        // User-assigned priority- lower priority drawn first
        // Equal- oldest (lowest ID) drawn first
        PROP_PRIORITY,
        
        PROP_LAST
    };
    RunData varTable[PROP_LAST];
    
protected:
    // World pointer not included, but will add if needed
    
    // Numeric ID- computer-generated- unique to world- nonzero
    int id;
    
    // Active sprites lock resources, etc.
    int active;
    void activateResource();
    void deactivateResource();

    friend struct ltSprite;
    
    // Entity that owns us- we don't own this ptr- can be NULL
    class Entity* obj;
    
    // Image (ready-to-blit; CAN point to a portion of a tileset, etc.)
    int width;
    int height;
    const class TextureMap* texture; // (see origImage)
    int texGraphic;

    // If non-NULL, image is our own
    // Also determines whether texture is our own
    SDL_Surface* origImage;
    
    // If non-NULL, image came from this tileset and tileset has been locked
    class TileSet* sourceTileSet;
    int tileNum; // Not gauranteed to be valid if above is NULL
    
    // If non-NULL, image came from this animation group (has been locked)
    // Single-image frames will also fill tileset, above
    class AnimGroup* sourceAnimGroup;
    int animNum; // Not gauranteed to be valid if above is NULL
    int animFrame; // Not gauranteed to be valid if above is NULL
    
    // @TODO:
    // Collision data
    // Color/alpha (4 separate values for optimized drawing)
    // Rotation, flip, other effects
    // Velocity, acceleration
    // Animation speed

public:
    // Id must be unique; use ID of 0 if we're going to load/create anyways
    // Can also use ID of 0 for internal temporaries, etc.
    Sprite(int myId = 0);
    ~Sprite();
    
    // Active sprites use resources; inactive do not (similar to locking
    // but no count is incremented- this is on or off only)
    void setActive();
    void setInactive();
    
    // Sets
    void setEntity(class Entity* newEntity) { obj = newEntity; }
    
    // Load a new image off a tileset/animation, or clear image
    void setImage(class TileSet* tileset, int tile);
    void setImage(class AnimGroup* animgroup, int anim, int frame);
    void setImage();
    
    // Movement
    void moveTo(int nX, int nY) { varTable[PROP_X].i = nX; varTable[PROP_Y].i = nY; }
    
    // Accessors
    int getId() const { return id; }
    int getX() const { return varTable[PROP_X].i; }
    int getY() const { return varTable[PROP_Y].i; }
    
    // Display
    void draw(int vX, int vY);
};

// For ordering sprites in priority queue
// @TODO: ensure reordering done on changing priority/scripttype
struct ltSprite {
    bool operator() (const Sprite* s1, const Sprite* s2) const {
        return (s1->varTable[Sprite::PROP_PRIORITY].i < s2->varTable[Sprite::PROP_PRIORITY].i) ||
               ((s1->varTable[Sprite::PROP_PRIORITY].i == s2->varTable[Sprite::PROP_PRIORITY].i) &&
                (s1->id < s2->id));
    }
};

// Hash for IDs- 1) as fast as possible 2) sorted iteration will be handled separately
typedef hash_map<int, Sprite*, hash<int> > SpriteIndex;
// List for sorted iteration- sorted by user priority, then ID
typedef std::set<Sprite*, ltSprite> SpriteOrder;

#endif

